package model.ai {
	import fs.util.RandomArray;
	import model.BitBoard;
	import model.GameData;
	import model.PiecesDefination;
	import model.Player;
	/**
	 * ...
	 * @author flyingSnow
	 */
	public final class GameNode {
		private var _gameData:GameData;
		private var _parent:GameNode;
		private var _consideringPlayer:int;
		
		private var _score:int = 0;
		
		private var _parentPath:Object = null;
		private var _bestChildPath:Object = null;
		
		private var _crntDepth:int = 0;
		private var _randPiece:Array;
		private var _randDr:Array;
		private var _checkedArray:Array;
		
		public static var totalDepth:int = 1;
		
		public function GameNode() {
			_checkedArray = [];
		}

		
		public function get gameData():GameData {
			return _gameData;
		}
		
		public function set gameData(value:GameData):void {
			_gameData = value.clone;
		}
		
		public function get parent():GameNode {
			return _parent;
		}
		
		private function get staticScore():int {
			var scr:Number = 0;
			if (_crntDepth >= totalDepth) {
				var sumScore:Number = 0;
				var sumLightPoints:Number = 0;
				for (var i:int = 0; i < 4; i++ ) {
					if (i == _consideringPlayer) {
						sumScore += _gameData.getPlayer(i).crntPieces.numSquares;
						sumLightPoints += _gameData.getPlayer(i).lightingPoints.numSquares;
					}else {
						//sumScore -= _gameData.getPlayer(i).crntPieces.numSquares/6;
						//sumLightPoints -= _gameData.getPlayer(i).lightingPoints.numSquares/6;
					}
				}
			
				var csdp:Player = _gameData.getPlayer(_consideringPlayer);
				var w:int = csdp.crntPieces.restrictWidth;
				var h:int = csdp.crntPieces.restrictHeight;
				scr +=sumScore+sumLightPoints -csdp.darkPoints.numSquares>>2+
						(w + h+1/(w / h+h / w));
			}
			return scr*100;
		}
		
		private function get subNodes():Array {
			_randPiece = RandomArray.getIntArray(0, PiecesDefination.PIECES_DEF.length);
			
			var nodes:Array = [];
			_checkedArray = _checkedArray.concat();
			var piecesNum:int = PiecesDefination.SIM_PIECES_DEF.length;
			for (var p:int = 0; p < piecesNum; p++ ) {
				var pi:int = _randPiece[p];
				_randDr = RandomArray.getIntArray(0, PiecesDefination.SIM_PIECES_DEF[pi].length);
				
				var drNum:int = PiecesDefination.SIM_PIECES_DEF[pi].length;		
				for (var d:int = 0; d < drNum; d++ ) {
					var dr:int = _randDr[d];
					for (var column:int = 0; column < BitBoard.BOARD_WIDTH; column++ ) {
						for (var row:int = 0; row < BitBoard.BOARD_WIDTH; row++ ) {
							var checkIndex:int=pi * 67200/*21*8*20*20*/+dr * 3200/*8*20*20*/+column * 20 + row;
							if (_checkedArray[checkIndex] != true &&									
									_gameData.canPutPiece(pi,dr,column,row)){
								if (!_gameData.crntPlayer.hasUsedPiece(pi) &&
									_gameData.crntPlayer.canPutPiece(pi, dr, column, row)){
									var gameNode:GameNode = new GameNode();
									gameNode.gameData = _gameData.clone;
									gameNode._gameData.crntPlayer.putPiece(pi,dr,column,row);
									gameNode._gameData.putPiece(pi, dr, column, row);
									gameNode._parent = this;
									gameNode._consideringPlayer = gameNode._gameData.crntPlayerIndex;
									gameNode._gameData.nextPlayer();
									gameNode._parentPath = { p:pi, d:dr, c:column, r:row };
									gameNode._crntDepth = _crntDepth + 1;
									gameNode._checkedArray = _checkedArray;
									nodes.push(gameNode);
								}
							}else {
								_checkedArray[checkIndex] = true;
							}
						}
					}
				}
			}			
			return nodes;
		}
		
		public function set consideringPlayer(value:int):void {
			_consideringPlayer = value;
		}
		
		public function get score():int {
			if (_crntDepth >= totalDepth) {
				return staticScore;
			}else {
				var subs:Array = subNodes;
				var maxNum:int = int.MIN_VALUE;
				for each(var node:GameNode in subs) {
					var s:int = node.score;
					if (maxNum < s) {
						maxNum = s;
						_bestChildPath = node.parentPath;
					}
				}
				return maxNum;
			}
			//return _score;
		}
		
		public function set score(value:int):void {
			_score = value;
		}
		
		public function get parentPath():Object {
			return _parentPath;
		}
		
		public function get bestChildPath():Object {
			return _bestChildPath;
		}
		
		public function set bestChildPath(value:Object):void {
			_bestChildPath = value;
		}
		
		public function crntPlayerIndex():int {
			return _gameData.crntPlayerIndex;
		}
	}

}